<?php
/**
 * Author：晴玖天
 * Creation：2020/5/30 14:07
 * Filename：VerificationCode.php
 * 验证码操作类
 */

namespace extend;


use Curl\Curl;
use FC\Captcha;

class VerificationCode
{

    /**
     * @param string $Name
     * @param int $num
     * @param int $w
     * @param int $h
     * @param int $size
     * 创建随机验证码
     */
    public static function RandomVerificationCode($Name = 'logins', $w = 240, $h = 80, $size = 28)
    {
        global $conf;
        if ((int)$conf['CaptchaType'] === 6) {
            $conf['CaptchaType'] = random_int(1, 5);
        }
        $ver = new Captcha();
        $ver->nums = 5;
        $ver->font_size = $size;
        $ver->width = $w;
        $ver->height = $h;
        $ver->font_path = ROOT . 'assets/fonts/title.otf';

        switch ((int)$conf['CaptchaType']) {
            case 2: //普通字母
                $ver->random = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM';
                break;
            case 3: //字母+数字
                break;
            case 4: //汉字
                $ver->random = self::getChar(10);
                $ver->font_path = ROOT . 'assets/fonts/names.otf';
                $ver->nums = 4;
                break;
            case 5: //运算符验证码
                $ver->font_path = ROOT . 'assets/fonts/names.otf';
                //$ver->is_gif = false;
                $type = random_int(1, 4);
                switch ($type) {
                    case 2: //减
                        $arr = self::RandomEvenNumber(1, 10);
                        $code = $arr[0] . '减' . $arr[1];
                        $count = $arr[0] - $arr[1];
                        break;
                    case 3: //乘
                        $arr = self::RandomEvenNumber(1, 10, 2);
                        $code = $arr[0] . '乘' . $arr[1];
                        $count = $arr[0] * $arr[1];
                        break;
                    case 4: //除
                        $arr = self::RandomEvenNumber(1, 10);
                        $code = ($arr[0] * $arr[1]) . '除' . $arr[0];
                        $count = ($arr[0] * $arr[1]) / $arr[0];
                        break;
                    default: //加
                        $arr = self::RandomEvenNumber(1, 10, 2);
                        $code = $arr[0] . '加' . $arr[1];
                        $count = $arr[0] + $arr[1];
                        break;
                }

                $_SESSION[$Name] = md5($count . href());
                break;
            case 7: //云端验证码
                self::getCloudVerificationCode($Name);
                break;
            default: //数字
                $ver->random = '123456789';
                break;
        }

        if ((int)$conf['CaptchaType'] !== 5) {
            $code = $ver->getCode();

            $_SESSION[$Name] = md5($code . href());

        }
        $ver->doImg($code);
    }

    //验证验证码是否有效
    public static function CaptchaValidation($Name, $Value)
    {
        global $conf, $_QET;
        if ($conf['CaptchaType'] == 8) {
            //极验验证
            if (!VerificationCode::Geetest($_QET['GT'])) {
                dies(-2, '验证失败，请重新验证！');
            }
            return true;
        }
        $keyfile = SYSTEM_ROOT . '/extend/log/Home/' . md5(userip() . href() . $Name) . '.key';
        //验证码无效化
        if ($conf['VerificationCodeSwitch'] == 2) {
            if ((int)$conf['CaptchaType'] != 7) {
                $_SESSION[$Name] = null;
            } else {
                unlink($keyfile);
            }
            return true;
        }
        if (empty($Value)) {
            return false;
        }
        if ((int)$conf['CaptchaType'] != 7) {
            //普通验证码
            if (empty($_SESSION[$Name]) || $_SESSION[$Name] <> md5($Value . href())) {
                $_SESSION[$Name] = null;
                return false;
            }
            $_SESSION[$Name] = null;
        } else {
            //云端验证码
            if (!file_exists($keyfile)) {
                return false;
            }
            $key = file_get_contents($keyfile);
            //验证码只能够使用一次
            unlink($keyfile);
            if ($key == '404') {
                //已失效验证码
                if ($Value == '404') {
                    return true;
                }
            }
            //开始验证
            $data = Curl::Get('api/Captcha/index', [
                'type' => 'validate',
                'key' => $key,
                'val' => $Value,
            ]);
            $data = json_decode($data, true);
            if (!$data || $data['code'] !== 200) {
                return false;
            }
        }
        return true;
    }

    //获取云端验证码
    public static function getCloudVerificationCode($Name)
    {
        mkdirs(SYSTEM_ROOT . '/extend/log/Home/');
        $keyfile = SYSTEM_ROOT . '/extend/log/Home/' . md5(userip() . href() . $Name) . '.key';
        //判断key文件是否存在
        if (!file_exists($keyfile)) {
            $data = Curl::Get('api/Captcha/index', [
                'type' => 'create',
            ]);
            $data = json_decode($data, true);
            if (!$data || $data['code'] !== 200) {
                file_put_contents($keyfile, 404);
                Header('HTTP/1.1 303 See Other');
                Header('Location: ' . href(2) . '/assets/img/404.png');
                die();
            }
            $key = $data['key'];
            file_put_contents($keyfile, $key);
        } else {
            //判断key文件是否过期，60秒
            $time = filemtime($keyfile);
            if (time() - $time > 60) {
                unlink($keyfile);
                self::getCloudVerificationCode($Name);
            }
            $key = file_get_contents($keyfile);
        }
        //通过key获取图片
        Curl::ImageGet('api/Captcha/index.php?type=display&key=' . $key);
        die();
    }

    /**
     * @param $min
     * @param $max
     * @param int $type
     * 返回随机双数
     */
    public static function RandomEvenNumber($min, $max, $type = 1)
    {
        $arr = [random_int($min, $max), random_int($min, $max)];
        if ($type === 1) {
            rsort($arr);
        }
        return $arr;
    }

    /**
     * @param $num
     * @return string
     * 随机汉字生成器
     */
    public static function getChar($num)
    {
        $b = '';
        for ($i = 0; $i < $num; $i++) {
            $a = chr(mt_rand(0xB0, 0xD0)) . chr(mt_rand(0xA1, 0xF0));
            $b .= iconv('GB2312', 'UTF-8', $a);
        }
        return $b;
    }

    //极验验证Api接口
    public static $GtUrl = 'http://gcaptcha4.geetest.com';

    /**
     * @param $GT //验证码参数
     * 验证极验验证码
     * @return bool
     */
    public static function Geetest($GT = [])
    {
        global $conf;
        if (!is_array($GT)) {
            $GT = json_decode($GT, true);
        }
        if ($conf['VerificationCodeSwitch'] == 2) {
            //验证码无效化验证开关
            return true;
        }
        test(['captcha_id', 'lot_number', 'pass_token', 'gen_time', 'captcha_output', 'name'], '请将参数提交完整！', $GT);
        if ($GT['captcha_id'] != $conf['GtCaptchaId']) {
            return false;
        }
        $postdata = [
            "lot_number" => $GT['lot_number'], //验证流水号
            "captcha_output" => $GT['captcha_output'], //验证输出信息
            "pass_token" => $GT['pass_token'], //验证通过标识
            "gen_time" => $GT['gen_time'], //验证通过时间戳
            "sign_token" => hash_hmac('sha256', $GT['lot_number'], $conf['GtCaptchaKey']) //验证签名
        ];
        $data = http_build_query($postdata);
        $options = array(
            'http' => array(
                'method' => 'POST',
                'header' => "Content-type: application/x-www-form-urlencoded",
                'content' => $data,
                'timeout' => 5
            )
        );
        $context = stream_context_create($options);
        $result = file_get_contents(sprintf(self::$GtUrl . "/validate" . "?captcha_id=%s", $conf['GtCaptchaId']), false, $context);
        if ($http_response_header[0] != 'HTTP/1.1 200 OK') {
            //接口请求失败,防止业务嘎了，默认成功
            return true;
        } else {
            //请求成功
            $json = json_decode($result, true);
            if ($json['result'] == 'success') {
                if (empty($json['captcha_args']['user_info']) || $json['captcha_args']['user_info'] != $GT['name']) {
                    return false;
                }
                return true;
            } else {
                return false;
            }
        }
    }
}